package pt.compflow.graph;

import pt.ipp.isep.gecad.onto2flow.model.Edge;
import pt.ipp.isep.gecad.onto2flow.model.O2F;
import pt.ipp.isep.gecad.onto2flow.model.Onto2FlowModel;
import pt.ipp.isep.gecad.onto2flow.model.Restriction;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;

public class OntModelGraphWrapper extends GraphWrapper {
	
	public OntModelGraphWrapper() {
		super();
	}

	public OntModelGraphWrapper(Onto2FlowModel model, String graphUri) {
		super(model, graphUri);
	}

	public OntModelGraphWrapper(Onto2FlowModel model) {
		super(model);
	}

	public OntModelGraphWrapper(String graphUri) {
		super(graphUri);
	}
	
	public Restriction addRestrictionEdge(Resource fromRes, Resource propRes, Resource toRes, boolean isPropertyCentric, boolean isHasValue, 
			boolean isSome, boolean isOnly, int exactCard, int minCard, int maxCard, boolean isClosure) {
		
		Edge e = addEdge(fromRes, propRes, toRes);
		if(e == null) return null;
		
		e.addProperty(RDF.type, O2F.Restriction);
		Restriction rest = e.as(Restriction.class);
		if(isPropertyCentric) rest.setPropertyCentric(true);
		if(isSome) rest.setSomeProp(true);
		if(isOnly) rest.setOnlyProp(true);
		if(exactCard >= 0) rest.setExactCardinality(exactCard);
		if(minCard >= 0) rest.setMinCardinality(minCard);
		if(maxCard >= 0) rest.setMaxCardinality(maxCard);	
		if(isHasValue) rest.setHasValue(true);
		if(isClosure) rest.setClosure(true);
		
		return rest;
	}
	
	@Override
	public void assimilate(GraphWrapper g) {
		QueryExecution qe = g.listEdges(null, null, null);
		ResultSet eIt = qe.execSelect();
		while(eIt.hasNext()) {
			Edge e = eIt.nextSolution().getResource("e").as(Edge.class);
			if(e.canAs(Restriction.class)) {
				Restriction r = e.as(Restriction.class);
				addRestrictionEdge(e.getFromNodeNode().getElement(), e.getProperty(), e.getToNodeNode().getElement(), 
						r.getPropertyCentric() != null && r.getPropertyCentric(), r.getHasValue() != null && r.getHasValue(), r.getSomeProp() != null && r.getSomeProp(),
						r.getOnlyProp() != null && r.getOnlyProp(), r.getExactCardinality() == null ? -1 : r.getExactCardinality(), 
						r.getMinCardinality() == null ? -1 : r.getMinCardinality(), r.getMaxCardinality() == null ? -1 : r.getMaxCardinality(),
								r.getClosure() != null && r.getClosure());
			} else
				addEdge(e.getFromNodeNode().getElement(), e.getProperty(), e.getToNodeNode().getElement());
		}
		qe.close();
	}	
	
	public QueryExecution listEdgesClosure(Resource fromClass, Resource propRes, Resource toRes) {
		return listEdgesClosure(fromClass, propRes, toRes, null);
	}
	
	public QueryExecution listEdgesClosure(Resource fromClass, Resource propRes, Resource toRes, Resource topSuperClassRes) {
			
		String superClassRest = "{{ BIND(<" + fromClass + "> as ?class) } UNION { <" + fromClass + "> <" + RDFS.subClassOf + ">+ ?class " + (topSuperClassRes == null ? "" : ". ?class <" + RDFS.subClassOf + ">+ <" + topSuperClassRes + ">") + " }} . ";
		
		String graphRest = "<" + graph.getURI() + "> <" + O2F.edge.getURI() + "> ?e . ";
		String fromRest = "?e <" + O2F.fromNode + "> ?n . ?n <" + O2F.element + "> ?class . ";
		String propertyRest = propRes == null ? null : "?e <" + O2F.property + "> <" + propRes.getURI() + "> . ";
		String toRest = toRes == null ? null : "?e <" + O2F.toNode + "> <" + toRes.getURI() + "-" + graph.getLocalName() + "> . ";
				
		String queryString = "SELECT ?e WHERE {  " + superClassRest + 
				graphRest + fromRest + (propertyRest != null ? propertyRest : "") + (toRest != null ? toRest : "") + " }";
		Query query = QueryFactory.create(queryString);
		QueryExecution qexec = QueryExecutionFactory.create(query, model);

		return qexec;
	}
	
}
